# 认证 RESTful API 控制器
from flask import request, current_app
from flask_restx import Resource, abort
from flask_jwt_extended import (
    jwt_required, get_jwt_identity, create_access_token, create_refresh_token,
    jwt_refresh_token_required, get_raw_jwt
)

from app.extensions import db
from app.models.user import User
from app.utils.response import success_response, error_response
from .. import auth_ns
from ..dto.auth_dto import (
    login_model, register_model, token_model, refresh_model,
    password_reset_request_model, password_reset_confirm_model,
    password_change_model
)

# 存储撤销的令牌（在生产环境中应使用Redis等）
revoked_tokens = set()

@auth_ns.route('/login')
class LoginResource(Resource):
    @auth_ns.doc('user_login')
    @auth_ns.expect(login_model, validate=True)
    @auth_ns.marshal_with(token_model)
    @auth_ns.response(401, '认证失败', error_response_model)
    def post(self):
        """用户登录"""
        data = request.get_json()
        username_or_email = data['username']
        password = data['password']
        
        # 查找用户（用户名或邮箱）
        user = User.query.filter(
            (User.username == username_or_email) | (User.email == username_or_email)
        ).first()
        
        # 验证用户和密码
        if not user or not user.check_password(password) or not user.is_active:
            abort(401, message='用户名/邮箱或密码错误')
        
        # 创建访问令牌和刷新令牌
        access_token = create_access_token(identity=user.id)
        refresh_token = create_refresh_token(identity=user.id)
        
        return {
            'access_token': access_token,
            'refresh_token': refresh_token,
            'token_type': 'Bearer',
            'expires_in': current_app.config['JWT_ACCESS_TOKEN_EXPIRES'].total_seconds()
        }

@auth_ns.route('/register')
class RegisterResource(Resource):
    @auth_ns.doc('user_register')
    @auth_ns.expect(register_model, validate=True)
    @auth_ns.marshal_with(token_model)
    @auth_ns.response(400, '无效请求', error_response_model)
    def post(self):
        """用户注册"""
        data = request.get_json()
        
        # 验证密码确认
        if data['password'] != data['confirm_password']:
            abort(400, message='密码和确认密码不匹配')
        
        # 检查用户名是否已存在
        if User.query.filter_by(username=data['username']).first():
            abort(400, message='用户名已存在')
        
        # 检查邮箱是否已存在
        if User.query.filter_by(email=data['email']).first():
            abort(400, message='邮箱已存在')
        
        # 创建新用户
        user = User(
            username=data['username'],
            email=data['email'],
            nickname=data.get('nickname', data['username'])
        )
        
        # 设置密码
        user.set_password(data['password'])
        
        # 保存到数据库
        db.session.add(user)
        db.session.commit()
        
        # 创建访问令牌和刷新令牌
        access_token = create_access_token(identity=user.id)
        refresh_token = create_refresh_token(identity=user.id)
        
        return {
            'access_token': access_token,
            'refresh_token': refresh_token,
            'token_type': 'Bearer',
            'expires_in': current_app.config['JWT_ACCESS_TOKEN_EXPIRES'].total_seconds()
        }, 201

@auth_ns.route('/refresh')
class RefreshResource(Resource):
    @auth_ns.doc('refresh_token')
    @auth_ns.expect(refresh_model, validate=True)
    @auth_ns.marshal_with(token_model)
    @auth_ns.response(401, '无效令牌', error_response_model)
    def post(self):
        """刷新访问令牌"""
        data = request.get_json()
        refresh_token = data['refresh_token']
        
        try:
            # 验证刷新令牌并获取用户ID
            from flask_jwt_extended import decode_token
            decoded_token = decode_token(refresh_token)
            user_id = decoded_token['identity']
            
            # 检查用户是否存在且激活
            user = User.query.get(user_id)
            if not user or not user.is_active:
                abort(401, message='无效用户')
            
            # 创建新的访问令牌
            access_token = create_access_token(identity=user_id)
            
            return {
                'access_token': access_token,
                'refresh_token': refresh_token,  # 刷新令牌可以重复使用
                'token_type': 'Bearer',
                'expires_in': current_app.config['JWT_ACCESS_TOKEN_EXPIRES'].total_seconds()
            }
        except Exception:
            abort(401, message='无效的刷新令牌')

@auth_ns.route('/logout')
class LogoutResource(Resource):
    @auth_ns.doc('user_logout')
    @auth_ns.marshal_with(success_response_model)
    @auth_ns.response(401, '未授权', error_response_model)
    @jwt_required()
    def post(self):
        """用户登出"""
        jti = get_raw_jwt()['jti']
        revoked_tokens.add(jti)
        return {'success': True, 'message': '成功登出'}

@auth_ns.route('/password-reset')
class PasswordResetResource(Resource):
    @auth_ns.doc('request_password_reset')
    @auth_ns.expect(password_reset_request_model, validate=True)
    @auth_ns.marshal_with(success_response_model)
    @auth_ns.response(404, '用户未找到', error_response_model)
    def post(self):
        """请求密码重置"""
        data = request.get_json()
        email = data['email']
        
        user = User.query.filter_by(email=email).first()
        if not user:
            # 为了安全，即使用户不存在也返回成功消息
            return {'success': True, 'message': '如果该邮箱存在，重置链接已发送'}
        
        # 在实际应用中，这里应该生成重置令牌并发送邮件
        # 为了示例，我们只返回成功消息
        return {'success': True, 'message': '如果该邮箱存在，重置链接已发送'}

@auth_ns.route('/password-reset/confirm')
class PasswordResetConfirmResource(Resource):
    @auth_ns.doc('confirm_password_reset')
    @auth_ns.expect(password_reset_confirm_model, validate=True)
    @auth_ns.marshal_with(success_response_model)
    @auth_ns.response(400, '无效请求', error_response_model)
    def post(self):
        """确认密码重置"""
        data = request.get_json()
        
        # 验证密码确认
        if data['new_password'] != data['confirm_password']:
            abort(400, message='密码和确认密码不匹配')
        
        # 在实际应用中，这里应该验证重置令牌
        # 为了示例，我们只返回成功消息
        return {'success': True, 'message': '密码重置成功'}

@auth_ns.route('/password-change')
class PasswordChangeResource(Resource):
    @auth_ns.doc('change_password')
    @auth_ns.expect(password_change_model, validate=True)
    @auth_ns.marshal_with(success_response_model)
    @auth_ns.response(401, '认证失败', error_response_model)
    @jwt_required()
    def post(self):
        """修改密码"""
        data = request.get_json()
        current_user_id = get_jwt_identity()
        user = User.query.get(current_user_id)
        
        # 验证旧密码
        if not user.check_password(data['old_password']):
            abort(401, message='旧密码不正确')
        
        # 验证新密码确认
        if data['new_password'] != data['confirm_password']:
            abort(400, message='新密码和确认密码不匹配')
        
        # 设置新密码
        user.set_password(data['new_password'])
        db.session.commit()
        
        return {'success': True, 'message': '密码修改成功'}